<?php

abstract class FormalizeField {
	
	/**
	 * Set properties for common data
	 * @var String
	 */
	private $type,
			$name,
			$label,
			$default;
			
	/**
	 * Flag wether this field is required or not
	 * @var Boolean
	 */
	private $required = false;
	
	/**
	 * Property to hold all filters that apply to the
	 * current field
	 * @var Array
	 */
	private $filters = array();
	
	/**
	 * List of attributes to add
	 * @var Array
	 */
	private $attributes = array();
	
	/**
	 * Optional property to store extra data, flags
	 * and/or attributes
	 * @var Mixed
	 */
	public $extra;
	
	/**
	 * The container HTML, to wrap the field html in
	 * @var String
	 */
	public $container;
	
	/**
	 * The HTML layout to use for rendering this field
	 * @var String
	 */
	protected $layout;
	
	/**
	 * Constructor method to set info and data
	 * @param String $type
	 * @param String $name
	 * @param String $label
	 * @param String $default
	 * @param Mixed $extra
	 */
	public function __construct($type, $name, $label=false, $default=false, $extra=false) {
		
		// Set label same as name if label is not set
		$label = (!$label) ? ucfirst($name) : $label;
		
		// Set the name, label, default value and extra parameters
		$this->type = $type;
		$this->name = $name;
		$this->label = $label;
		$this->default = $default;
		$this->extra = $extra;
		
		// Set default field html if not set
		if (!$this->layout) {
			$this->layout = '<input type="[_TYPE_]" name="[_NAME_]" id="[_NAME_]" value="[_DEFAULT_]" [_ATTRIBS_] />';
		}
	}
	
	/**
	 * Method to set the current field to required or not
	 * @param Boolean $flag
	 */
	public function setRequired($flag=true) {
		
		// Set the required flag
		$this->required = (bool) $flag;
	}
	
	/**
	 * Method to add a filter object to the current field.
	 * Throws a user error if the filter does not exists
	 * @param String $name
	 * @param String $settings
	 */
	public function addFilter($name, $settings=false) {
		
		// Construct a classname
		$filterClassName = 'Filter'.ucfirst($name);
		
		// Check if the class already exists, try to
		// lazy load it otherwise
		if (!class_exists($filterClassName)) {
			
			// Set filename to the class file
			$filterClassFile = strtolower($name).'.filter.php';
			$filterClassPath = dirname(dirname(__FILE__)).'/filters/'.$filterClassFile;
			
			// Check if the file exists, set additional error
			if (!file_exists($filterClassPath)) {
				
				// Throw user error if the filter does not exists
				trigger_error('No file or class does exists for filter '.$name, E_USER_ERROR);
				exit;
			}
			
			// Load the file for the class
			require_once $filterClassPath;
		}
		
		// Construct the filter class with the optional settings
		// and add it to the filters array
		$this->filters[] = new $filterClassName($settings);
	}
	
	/**
	 * Method to add multiple filters at once with an array
	 * @param Array $filters
	 */
	public function addFilters($filters) {
		
		// Stop if param is not an array
		if (!is_array($filters)) return false;
		
		// Loop through the filters and add them
		foreach ($filters as $filterName => $filterSettings) {
			
			$this->addFilter($filterName, $filterSettings);
		}
	}
	
	/**
	 * Method to set an attribute for the current field's HTML
	 * @param String $key
	 * @param String $val
	 */
	public function setAttribute($key, $val) {
		
		// Add the current combination to the attributes array
		$this->attributes[$key] = $val;
	}
	
	/**
	 * Method to merge the current attribute array with given one
	 * @param Array $attribs
	 */
	public function setAttributes($attribs) {
		
		// Stop if the attribs is not an array
		if (!is_array($attribs)) return false;
		
		// Add all attributes to the atribute array
		$this->attributes = array_merge($this->attributes, $attribs);
	}
	
	/**
	 * Method to render the html of the current field with
	 * the current options
	 * @return String
	 */
	public function render() {
		
		// Start with default HTML
		$html = $this->container;
		$field = $this->layout;
		
		// Render the html for the attributes, if needed.
		$attribs = '';
		if ($this->attributes) {
			
			foreach ($this->attributes as $attrib => $attribVal) {
				
				$attribs .= "{$attrib}=\"{$attribVal}\" ";
			}
		}
		
		// Set array with replacements
		$replacements = array(
			'type' => $this->type,
			'name' => $this->name,
			'label' => $this->label,
			'default' => $this->default,
			'attribs' => $attribs
		);
		
		// Loop through the replacements and render the correct field
		foreach ($replacements as $key => $value) {
				
			// Set correct key
			$key = '[_'.strtoupper($key).'_]';
			
			// Replace the key with the correct value
			$field = str_replace($key, $value, $field);
		}
		
		// Set replacements for the container html
		$containerReplacements = array(
			'name' => $this->name,
			'label' => $this->label,
			'field' => $field
		);
		
		// Loop through the replacements and render the correct field
		foreach ($containerReplacements as $key => $value) {
				
			// Set correct key
			$key = '[_'.strtoupper($key).'_]';
			
			// Replace the key with the correct value
			$html = str_replace($key, $value, $html);
		}
		
		// Eventually, return the HTML
		return $html;
	}
}
